Skip to contentMethod: lambda$of$0(Class, String)
1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * SteelBlue: DCI User Interfaces
5: * http://tidalwave.it/projects/steelblue
6: *
7: * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/steelblue-src
22: * git clone https://github.com/tidalwave-it/steelblue-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.ui.javafx.impl;
27:
28: import jakarta.annotation.Nonnull;
29: import java.io.IOException;
30: import java.io.UncheckedIOException;
31: import javafx.fxml.FXMLLoader;
32: import javafx.scene.Node;
33: import it.tidalwave.ui.javafx.NodeAndDelegate;
34: import it.tidalwave.ui.javafx.impl.util.JavaFXSafeProxy;
35: import it.tidalwave.ui.javafx.spi.AbstractJavaFXSpringApplication;
36: import org.slf4j.LoggerFactory;
37: import lombok.Getter;
38: import lombok.RequiredArgsConstructor;
39: import lombok.extern.slf4j.Slf4j;
40: import static it.tidalwave.ui.javafx.impl.DefaultJavaFXBinder.enforceFxApplicationThread;
41: import static it.tidalwave.ui.javafx.impl.util.JavaFXSafeRunner.runSafelyAndWait;
42: import static it.tidalwave.util.ReflectionUtils.*;
43:
44: /***************************************************************************************************************************************************************
45: *
46: * The implementation of {@link NodeAndDelegate}.
47: *
48: * @author Fabrizio Giudici
49: *
50: **************************************************************************************************************************************************************/
51: @RequiredArgsConstructor @Getter @Slf4j
52: public class DefaultNodeAndDelegate<T> implements NodeAndDelegate<T>
53: {
54: @Nonnull
55: private final Node node;
56:
57: @Nonnull
58: private final T delegate;
59:
60: /***********************************************************************************************************************************************************
61: * Creates a {@link NodeAndDelegate} for the given presentation class. The FXML resource name is inferred by default, For instance, is the class is named
62: * {@code JavaFXFooBarPresentation}, the resource name is {@code FooBar.fxml} and searched in the same packages as the class.
63: * @param presentationClass the class of the presentation for which the resources must be created.
64: * @since 1.0-ALPHA-13
65: * @see #of(java.lang.Class, java.lang.String)
66: **********************************************************************************************************************************************************/
67: @Nonnull
68: public static <T> NodeAndDelegate<T> of (@Nonnull final Class<T> presentationClass)
69: {
70: final var resource = presentationClass.getSimpleName().replaceAll("^JavaFX", "")
71: .replaceAll("^JavaFx", "")
72: .replaceAll("Presentation$", "")
73: + ".fxml";
74: return of(presentationClass, resource);
75: }
76:
77: /***********************************************************************************************************************************************************
78: * Creates a {@link NodeAndDelegate} for the given presentation class.
79: * @param presentationClass the class of the presentation for which the resources must be created.
80: * @param fxmlResourcePath the path of the FXML resource
81: **********************************************************************************************************************************************************/
82: @Nonnull
83: public static <T> NodeAndDelegate<T> of (@Nonnull final Class<T> presentationClass, @Nonnull final String fxmlResourcePath)
84: {
85: try
86: {
87: log.debug("of({}, {})", presentationClass, fxmlResourcePath);
88: return runSafelyAndWait(() -> load(presentationClass, fxmlResourcePath));
89: }
90: catch (RuntimeException e)
91: {
92: throw e;
93: }
94: catch (Exception e)
95: {
96: throw new RuntimeException(e);
97: }
98: }
99:
100: /***********************************************************************************************************************************************************
101: *
102: **********************************************************************************************************************************************************/
103: @Nonnull
104: private static <T> NodeAndDelegate<T> load (@Nonnull final Class<T> clazz, @Nonnull final String resource)
105: {
106: try
107: {
108: enforceFxApplicationThread();
109: final var log = LoggerFactory.getLogger(NodeAndDelegate.class);
110: log.debug("NodeAndDelegate({}, {})", clazz, resource);
111: final var loader = new FXMLLoader(clazz.getResource(resource), null, null, type -> instantiateWithDependencies(type, AbstractJavaFXSpringApplication.getBeans()));
112: final Node node = loader.load();
113: final T jfxController = loader.getController();
114: injectDependencies(jfxController, AbstractJavaFXSpringApplication.getBeans());
115: final var interfaces = jfxController.getClass().getInterfaces();
116:
117: if (interfaces.length == 0)
118: {
119: log.warn("{} has no interface: not creating safe proxy", jfxController.getClass());
120: }
121:
122: final T delegate = (interfaces.length > 0) ? JavaFXSafeProxy.of(jfxController, interfaces) : jfxController;
123: log.debug(">>>> load({}, {}) completed", clazz, resource);
124: return new DefaultNodeAndDelegate<>(node, delegate);
125: }
126: catch (IOException e)
127: {
128: throw new UncheckedIOException(e);
129: }
130: catch (IllegalStateException e)
131: {
132: final var message = String.format("ERROR: Cannot find resource: %s/%s", clazz.getPackageName().replace('.','/'), resource);
133: log.error("ERROR: Cannot find resource: {}", message);
134: throw new IllegalStateException(message, e);
135: }
136: }
137: }